#coding: utf8
'''
==================================================================================
Created on 2020-10-26
Author: Simon
==================================================================================
'''

from datetime import datetime, timedelta
from src.libs.database import Database
from src.task import get_task_ctls
from src.common.base import workday as WD, today, next_day, weekday, id_null, \
    get_user_level, get_user_org, monthSection, quarterSection


def is_today(tm): return WD()[:10] == str(tm)[:10]
def pre_days(count=7):
    return str(datetime.now() - timedelta(days = count))[:10]
def f(d): return d if d else ""


'''
获取正在进行中的任务，兼容部门和个人
三种情况：
    1、计划中有且未提交过的非正式任务（未建任务，无任务ID）；
    2、建过任务且未提交过记录；
    3、已提交过日志的未完成任务；
TODO: 性能优化
    任务完成后，更改record_day表相关记录状态
'''
def list_task_left(user=None, department=None, db=None):
    if not db: db = Database()
    whrs = ['', '', ''] if department else ['p.user=%s and ', 
                        't.executor=%s and ', ' and user=%s']
    '''TODO：增补任务完成100%后又修改任务计划重新评估任务进度情况'''
    sql = '''
    select p.category, -1 projectId, -1 moduleId, -1 taskId, p.project project, 
        p.module module, p.task task, 0 progress, p.createTime time, p.user user 
        from plan_day p 
        left join record_day r on p.project=r.project and p.module=r.module and p.task=r.task 
        where {} p.taskId is null and r.id is null
    union all
    select 0, t.projectId, t.moduleId, t.id, p.name, m.name, t.name, 0, t.createTime, 
        t.executor from task t left join record_day r on t.id=r.taskId 
        left join project p on p.id=t.projectId
        left join module m on m.id=t.moduleId
        where {} t.status=0 and r.id is null
    union all
    select * from (SELECT category, projectId, moduleId, taskId, project, module, 
        task, progress, updateTime tm, user from record_day a 
            where taskStatus=0 and updateTime=(select max(updateTime) from record_day b 
            where a.project=b.project and a.module=b.module and a.task=b.task)
    ) r where r.progress<100 {} 
    order by time desc
    '''.format(*whrs)
    
    if department:
        sql = "select d.* from (" + sql + ") d join user u on d.user=u.username where u.orgId=%s" 
    params = [department] if department else [user, user, user]
    
    data = db.read_all(sql, params)
    for line in data: line['time'] = str(line['time'])
    
    return data
    

'''列出最近几天日报'''
def list_report_day(user=None, department=None):
    r = Report()
    return r.list_report_day(user, department)

'''获取某天日报'''
def get_report_day(user=None, department=None, workday=None):
    r = Report()
    records = r.get_report_list("record", user, department, workday)
    plans = r.get_report_list("plan", user, department, workday)
    data = {'job': [], 'plan': []}
    if records: data['job'] = list(records.values())[0]
    if plans: data['plan'] = list(plans.values())[0] 
    
    return data

'''所有记录汇总日志'''
def get_report_proj_com(begin_time, end_time, department=None):
    
    return get_report_common(begin_time, end_time, None, department)

'''当日所有记录汇总日志'''
def get_report_proj_day(day=None, department=None):
    begin_time = day if day else today()[:10]
    end_time = next_day(day)
    
    return get_report_common(begin_time, end_time, None, department)

'''当日所有记录汇总日志'''
def get_report_month(month=None, user=None, department=None):
    begin_time, end_time = monthSection()
    
    res = get_report_common(begin_time, end_time, user, department)
    res['key'] = res['key'].replace("_", "-")
    return res
    
def get_report_week(begin_time, end_time, user=None, department=None):
    r = Report()
    if not begin_time: begin_time, end_time = weekday()
    record = r.get_report_period(begin_time, end_time, user, department)
    
    data = {'record': record, 'plan': '', 
            'key': ("%s_%s" % (begin_time, end_time)).replace("-", ".").replace("_", "-"), 
            "btime": begin_time, 'eTime': end_time}
    
    return data

def get_report_quarter(quarter, user=None, department=None):
    begin_time, end_time = quarterSection()
    r = Report()
    record = r.get_report_period(begin_time, end_time, user, department)
    key = "%s_%s" % (begin_time[:10], end_time[:10])
    data = {'record': record, 'plan': '', 
            'key': key.replace("-", "").replace("_", "-"), 
            "btime": begin_time, 'eTime': end_time}
    return data

def get_report_com(begin_time, end_time, user=None, department=None):
    r = Report()
    record = r.get_report_period(begin_time, end_time, user, department)
    key = "%s_%s" % (begin_time[:10], end_time[:10])
    data = {'record': record, 'plan': '', 
            'key': key.replace("-", "").replace("_", "-"), 
            "btime": begin_time, 'eTime': end_time}
    return data

def get_report_common(begin_time, end_time, user=None, department=None):
    r = Report()
    record = r.get_report_period(begin_time, end_time, user, department)
    
    data = {'record': record, 'plan': '', 
            'key': ("%s_%s" % (begin_time, end_time)).replace("-", ""), 
            "btime": begin_time, 'eTime': end_time}
    
    return data 

'''加载剩余未完成的任务'''
def load_left_records(user, js, ps):
    db = Database()
    dts = list_task_left(user, None, db)
    js, ps = set(js), set(ps)
    
    rs = {'job': [], 'plan': []}
    for d in dts:
        if id_null(d['taskId']): continue
        key = "$_$".join(f(s) for s in (d['project'], d['module'], d['task']))
        if key in js: rs['job'].append(d)
        if key in ps: rs['plan'].append(d)
    return _load_rel_records(user, rs, db)
    
    

'''
    修改已提交的日志，逻辑比较复杂。
    1、为前端一次性加载所有关联的基础信息；
    2、在任务的状态控制方面，需排除本人本日已提交日志再来分析任务的最低进度；
'''
def load_records(user):
    db = Database()
    '''仅支持修改今日日志'''
    workday = WD()
    rs = get_report_day(user, None, workday)
    
    return _load_rel_records(user, rs, db)
    
'''通过已知数据集，加载所需依赖'''
def _load_rel_records(user, rs, db):
    if not rs['job'] and not rs['plan']: return {'records': None}
    dts = rs['job'] + rs['plan']    
    ps = list(set(d['projectId'] for d in dts if not id_null(d['projectId'])))
    ms = list(set(d['moduleId'] for d in dts if not id_null(d['moduleId'])))
    ts = list(set(d['taskId'] for d in dts if not id_null(d['taskId'])))
    
    sql = "select id, name, projectId, status, createUser from module where \
        projectId in ({})".format(','.join('%s' for p in ps))
    modules = db.read_all(sql, ps)
    
    sql = "select id, name, projectId, moduleId, executor, multiUser, progress \
         from task where moduleId in ({})".format(','.join('%s' for m in ms))
    tasks = db.read_all(sql, ms)
    
    ctls = get_task_ctls(user, ts, db)
    
    data = {'records': rs, 'modules': modules, 'tasks': tasks, 'ctls': ctls}
    
    return data
         
    
    
class Report():
    def __init__(self):
        pass
    
    '''获取近七天日报'''
    def list_report_day(self, user=None, department=None):
        records = self.get_report_list("record", user, department)
        plans = self.get_report_list("plan", user, department)
        
        dts = {}
        for workday, rs in records.items():
            if workday not in dts: 
                dts[workday] = {'workday': workday, "plan": "", "pcount": 0}
            dts[workday]['record'] = self.collect_data(rs, "record", True, department)
            dts[workday]['rcount'] = len(rs)
            
        for workday, ps in plans.items():
            if workday not in dts: continue
            dts[workday]['plan'] = self.collect_data(ps, "plan", True, department)
            dts[workday]['pcount'] = len(ps)
        
        lines = sorted(dts.values(), key=lambda x:x["workday"], reverse=True)
        
        return lines 
    
    '''***主要获取日报原始内容过程***'''
    def _get_report(self, key="record", user=None, department=None, workday=None):
        db = Database()
        table = "record_day" if key == "record" else "plan_day"
        params = [pre_days(), pre_days(-1)]
        
        sql = '''select user, workday, project, module, task, content, keycode,
            r.projectId projectId, r.moduleId moduleId, r.taskId taskId,
            r.progress progress, r.category category, r.updateTime, planEndTime from {} r 
            left join task t on t.id=r.taskId 
            where workday between %s and %s'''.format(table)
        if user:
            sql += " and user=%s"
            params.append(user)
        if workday:
            sql += " and workday=%s"
            params.append(str(workday)[:10])
        if department:
            sql += " and user in (select username from user where orgId=%s)"
            params.append(department)
        sql += " order by project"
        res = db.read_all(sql, params)
        
        return res
    
    '''周期性汇总
    * 同一个任务在周期内会被提交多次，以最后一条数据的进度为准，所以要取每项任务的最新数据。
    * 带 department 参数则统计整个部门，否则只统计个人
    注：以下两种方式取最新记录的效率分析
        法1：SELECT * FROM record_day a where updateTime=(select max(updateTime) from 
            record_day b where a.task=b.task)
        法2：SELECT * FROM (SELECT task, max(updateTime) tm from record_day group by task) a 
            LEFT JOIN record_day r on a.task=r.task and r.updateTime=tm
    '''
    def select_report_period(self, begin_time, end_time, user=None, department=None):
        db = Database()
        params = [begin_time, end_time]
        sql = '''
        SELECT user, workday, project, module, task, a.progress, a.category,
            updateTime, planEndTime FROM record_day a left join user u on u.username=a.user
            left join task t on a.taskId=t.id
            where updateTime=(select max(updateTime) from record_day b 
                where a.project=b.project and a.module=b.module 
            and a.task=b.task and workday between %s and %s {})
        '''
        if department:
            sql = sql.format("and orgId=%s")
            params.append(department)
        elif user:
            sql = sql.format("and user=%s")
            params.append(user)
        else:
            sql = sql.format("")
        sql += "order by project, module, task, updateTime"
        res = db.read_all(sql, params)
        
        return res
    
    def get_report_period(self, begin_time, end_time, user=None, department=None):
        res = self.select_report_period(begin_time, end_time, user, department)
        records = self.collect_data(res, "record", False, department)
        
        '''TODO： 按项目排序'''
                
        # lines = sorted(dts.values(), key=lambda x:x["workday"], reverse=True)
        
        return records
    
    '''完成内容 & 计划通用过程·从数据库获取记录'''
    def get_report_list(self, key="record", user=None, department=None, workday=None):
        res = self._get_report(key, user, department, workday)
        
        '''按天归类'''
        dts = {}
        for d in res:
            if d['planEndTime']: d['planEndTime'] = str(d['planEndTime'])
            if d['updateTime']: d['updateTime'] = str(d['updateTime'])
            
            day = d['workday'] = str(d['workday'])[:10]
            if day not in dts: dts[day] = []
            dts[day].append(d)
        '''End For'''
        
        return dts

    '''将一天的日志汇总并格式化'''
    def collect_data(self, records, key="record", daily=True, department=1):
        projects = {}
        '''按项目汇总'''
        for d in records:
            pj = d['project'] if d['project'] else "其它" 
            if pj not in projects: projects[pj] = []
            line = "%s.%s；" % (len(projects[pj]) + 1, format_report(d, key, daily))
            projects[pj].append(line)
            
        content = ""
        idx, nums = 0, ['', '一', '二', '三', '四', '五', '六', '七', '八', '九', '十', '十一',
                        '十二', '十三', '十四', '十五', '十六', '十七', '十八']
        pc = len(projects)
        for name, vs in projects.items():
            idx += 1
            pname = "%s、%s" % (nums[idx], name)
            '''技术部：[(%s)、%s]'''
            content += pname + "<br>%s<br> " % ("<br>".join(vs))
        
        return content

'''-----------------------------------End Class------------------------------'''    

def format_report(line, key="record", daily=True):
    if key == "record": return format_record(line, daily)
    if key == "plan": return format_plan(line)

'''计划格式化过程'''
def format_plan(line):
    p, m = int(line['progress']), f(line['module'])
    if m=='其它': m = ''
    main = m + ('' if m=='' else '-') + line['task']
    plan = "，预计完成{}%".format(p)
    return main + plan
    
'''日志格式化核心过程'''    
def format_record(line, daily=True):    
    if not line['planEndTime']: line['planEndTime'] = line['updateTime'] 
    p, ptm = int(line['progress']), str(line['planEndTime'])[5:10]
    m = f(line['module'])
    if m=='其它': m = '' 
    main = m + ('' if m=='' else '-') + line['task']
    '''外出'''
    if int(line['category']) == 3: main = "外出%s，" % m + main 
    plan = "，计划%s完成" % ("今日" if daily and is_today(ptm) else ptm)
    prog = "，已完成" if p == 100 else "，完成{}%".format(p)
    '''具体工作细节，日报显示，周报不显示'''
    detail = "<br>(%s)" % line['content'] if daily and f(line['content']) != "" else ""  
    return main + plan + prog + detail







    



if __name__ == '__main__':
    # d = list_report_day("liuhong")
    
    # d = get_report_day(None, None, "2021-10-14")
    # d = is_today(datetime.now())
    # d = load_record("admin", "2021-10-14")
    
    # get_report_week("2021-10-14", "2021-10-21", "liuhong")
    # d = get_report_week("2022-03-28", "2023-04-04", None, 1)
    # d = get_report_week(None, None, None, 1)
    # d = list_task_left("liuhong", None)
    # d = load_left_records("liuhong", [], [])
    d = get_report_proj_day("2022-07-05")
    # d = get_report_proj_month()
    # d = get_report_quarter(1)
    print(d)
    
    pass

